// MValue.cpp : Implementation of CMudosApp and DLL registration.

#include "stdafx.h"
#include "m.h"

/////////////////////////////////////////////////////////////////////////////
//


STDMETHODIMP CMValue::get_Name(BSTR * pVal)
{
	// TODO: Add your implementation code here
	if(!pVal)return S_FALSE;
	if(parent){
		Cc2w c2w;
		c2w.in(parent->u.ob->prog->variable_table[m_id]);
		*pVal=SysAllocString(c2w.out());
	} else {
		*pVal=NULL;
	}
	return S_OK;
}

VALUETYPE ToOleType(unsigned short t)
{
	if(t==T_NUMBER)  return VP_NUMBER;
	if(t==T_STRING)  return VP_STRING;
	if(t==T_REAL)    return VP_REAL;
	if(t==T_OBJECT)  return VP_OBJECT;
	if(t==T_FUNCTION)return VP_FUNCTION;
	if(t==T_BUFFER)  return VP_BUFFER;
	if(t==T_ARRAY)   return VP_ARRAY;
	if(t==T_CLASS)   return VP_CLASS;
	if(t==T_MAPPING) return VP_MAPPING;
	return VP_UNKNOW;
}

VALUETYPE CMValue::Type()
{
	return ToOleType(GetSValue()->type);
}

STDMETHODIMP CMValue::get_Type(VALUETYPE * pVal)
{
	// TODO: Add your implementation code here
	if(!pVal)return S_FALSE;
	*pVal=Type();
	return S_OK;
}

STDMETHODIMP CMValue::CreateNumber()
{
	if(m_id>=0){
		if(GetSValue()->type==T_INVALID){
			GetSValue()->type=T_NUMBER;
			return S_OK;
		}
		return S_FALSE;
	}
	st.type=T_NUMBER;
	m_id=0;
	return S_OK;
}

STDMETHODIMP CMValue::CreateString()
{
	if(m_id>=0){
		if((GetSValue()->type==T_INVALID)||(GetSValue()->type==T_NUMBER)){
			GetSValue()->type=T_STRING;
			GetSValue()->u.string=0;
			return S_OK;
		}
		return S_FALSE;
	}
	st.type=T_STRING;
	m_id=0;
	return S_OK;
}

STDMETHODIMP CMValue::CreateReal()
{
	if(m_id>=0){
		if((GetSValue()->type==T_INVALID)||(GetSValue()->type==T_NUMBER)){
			GetSValue()->type=T_REAL;
			return S_OK;
		}
		return S_FALSE;
	}
	st.type=T_REAL;
	m_id=0;
	return S_OK;
}

extern "C" array_t *   _allocate_array(int);
extern "C" mapping_t * _allocate_mapping(int);

STDMETHODIMP CMValue::CreateArray(int size)
{
	if(m_id>=0){
		if((GetSValue()->type==T_INVALID)||(GetSValue()->type==T_NUMBER)){
			GetSValue()->type=T_ARRAY;
			GetSValue()->u.arr=_allocate_array(size);
			return S_OK;
		}
		return S_FALSE;
	}
	st.type=T_ARRAY;
	st.u.arr=_allocate_array(size);
	m_id=0;
	return S_OK;
}

STDMETHODIMP CMValue::CreateMapping()
{
	if(m_id>=0){
		if((GetSValue()->type==T_INVALID)||(GetSValue()->type==T_NUMBER)){
			GetSValue()->type=T_MAPPING;
			GetSValue()->u.map=_allocate_mapping(0);
			return S_OK;
		}
		return S_FALSE;
	}
	st.type=T_MAPPING;
	st.u.map=_allocate_mapping(0);
	m_id=0;
	return S_OK;
}


STDMETHODIMP CMValue::get_ItemCount(/*[out, retval]*/ int *pVal)
{
	if(!pVal)return S_FALSE;
	if(Type()==VP_ARRAY){
		array_t *p;
		p=GetSValue()->u.arr;
		if(p)*pVal=p->size;
		return S_OK;
	}
	return S_FALSE;
}

STDMETHODIMP CMValue::get_MemberCount(/*[out, retval]*/ int *pVal)
{
	if(!pVal)return S_FALSE;
	if(Type()==VP_CLASS){
		class_t *p;
		p=GetSValue()->u.cls;
		if(p)*pVal=p->size;
		return S_OK;
	}
	return S_FALSE;
}

STDMETHODIMP CMValue::get_Item(/*[in]*/ int id, /*[out, retval]*/ IMValue * *pVal)
{
	if(!pVal)return S_FALSE;
	if(Type()==VP_ARRAY){
		array_t *p;
		p=GetSValue()->u.arr;
		if(!p)return S_FALSE;
		if((id<0)||(id>=p->size))return S_FALSE;
		CComObject<CMValue> *o;
		o=new CComObject<CMValue>;
		o->AddRef();
		o->CreateRef(GetSValue(),id);
		*pVal=o;
		return S_OK;
	}
	return S_FALSE;
}

extern "C" void _free_empty_array P1(array_t *, p);

STDMETHODIMP CMValue::get_NewItem(IMValue **pVal)
{
	// TODO: Add your implementation code here
	if(!pVal)return S_FALSE;
	if(Type()==VP_ARRAY){
		array_t *p;
		p=GetSValue()->u.arr;
		if(!p)return S_FALSE;
		GetSValue()->u.arr=_allocate_array(p->size+1);
		if(!GetSValue()->u.arr)return S_FALSE;
		if(p->size>0)
			memcpy(&GetSValue()->u.arr->item,&p->item,sizeof(svalue_t) * (p->size));
		_free_empty_array(p);
		p=GetSValue()->u.arr;
		p->item[p->size-1].type=T_INVALID;

		CComObject<CMValue> *o;
		o=new CComObject<CMValue>;
		o->AddRef();
		o->CreateRef(GetSValue(),p->size-1);
		*pVal=o;
		return S_OK;
	}
	return S_OK;
}

STDMETHODIMP CMValue::get_Member(/*[in]*/ int id, /*[out, retval]*/ IMValue * *pVal)
{
	if(!pVal)return S_FALSE;
	if(Type()==VP_CLASS){
		class_t *p;
		p=GetSValue()->u.cls;
		if(!p)return S_FALSE;
		if((id<0)||(id>=p->size))return S_FALSE;
		CComObject<CMValue> *o;
		o=new CComObject<CMValue>;
		o->AddRef();
		o->CreateRef(GetSValue(),id);
		*pVal=o;
		return S_OK;
	}
	return S_FALSE;
}


STDMETHODIMP CMValue::get_ObjectName(BSTR * pVal)
{
	// TODO: Add your implementation code here
	if(!pVal)return S_FALSE;
	if(Type()!=VP_OBJECT)return S_FALSE;
	object_t *o;
	o=GetSValue()->u.ob;
	if(o){
		Cc2w c2w;
		c2w.in(o->name);
		*pVal=SysAllocString(c2w.out());
	}
	return S_OK;
}

STDMETHODIMP CMValue::get_ObjectLoadTime(int * pVal)
{
	// TODO: Add your implementation code here
	if(!pVal)return NULL;
	if(Type()!=VP_OBJECT)return S_FALSE;
	object_t *o;
	o=GetSValue()->u.ob;
	if(o){
		*pVal=o->load_time;
	}
	return S_OK;
}



STDMETHODIMP CMValue::get_Environment(IMObject * * pVal)
{
	// TODO: Add your implementation code here
	if(!pVal)return NULL;
	if(Type()!=VP_OBJECT)return S_FALSE;
	object_t *p;
	p=GetSValue()->u.ob;
	if(p){
		svalue_t st;
		st.type=T_OBJECT;
		st.u.ob=p->super;
		CComObject<CMValue> *o;
		o=new CComObject<CMValue>;
		o->AddRef();
		o->Create(&st);
		*pVal=o;
	}
	return S_OK;
}

STDMETHODIMP CMValue::get_ValueCount(int * pVal)
{
	// TODO: Add your implementation code here
	if(!pVal)return S_FALSE;
	if(Type()!=VP_OBJECT)return S_FALSE;
	object_t *p;
	p=GetSValue()->u.ob;
	if(p){
		*pVal=p->prog->num_variables_total;
	}
	return S_OK;
}

STDMETHODIMP CMValue::get_Value(int id, IMValue * * pVal)
{
	// TODO: Add your implementation code here
	if(!pVal)return S_FALSE;
	if(Type()!=VP_OBJECT)return S_FALSE;
	object_t *p;
	p=GetSValue()->u.ob;
	if(p){
		if((id<0)||(id>=p->prog->num_variables_total))return S_FALSE;
		CComObject<CMValue> *o;
		o=new CComObject<CMValue>;
		o->CreateRef(GetSValue(),id);
		o->AddRef();
		*pVal=o;
	}
	return S_OK;
}


STDMETHODIMP CMValue::get_Number(int * pVal)
{
	// TODO: Add your implementation code here
	if(!pVal)return S_FALSE;
	if(Type()!=VP_NUMBER)return S_FALSE;
	*pVal=GetSValue()->u.number;
	return S_OK;
}

STDMETHODIMP CMValue::put_Number(int newVal)
{
	// TODO: Add your implementation code here
	if(Type()!=VP_NUMBER)return S_FALSE;
	GetSValue()->u.number=newVal;
	return S_OK;
}

STDMETHODIMP CMValue::get_Real(float * pVal)
{
	// TODO: Add your implementation code here
	if(!pVal)return S_FALSE;
	if(Type()!=VP_REAL)return S_FALSE;
	*pVal=GetSValue()->u.real;
	return S_OK;
}

STDMETHODIMP CMValue::put_Real(float newVal)
{
	// TODO: Add your implementation code here
	if(Type()!=VP_REAL)return S_FALSE;
	GetSValue()->u.real=newVal;
	return S_OK;
}

STDMETHODIMP CMValue::get_String(BSTR * pVal)
{
	// TODO: Add your implementation code here
	if(!pVal)return S_FALSE;
	if(Type()!=VP_STRING)return S_FALSE;
	Cc2w c2w;
	c2w.in(GetSValue()->u.string);
	*pVal=SysAllocString(c2w.out());
	return S_OK;
}

extern "C" void _replace_string(char **s,char *p);

STDMETHODIMP CMValue::put_String(BSTR newVal)
{
	// TODO: Add your implementation code here
	if(Type()!=VP_STRING)return S_FALSE;
	Cw2c w2c;
	w2c.in(newVal);
	GetSValue()->subtype=STRING_MALLOC;
	_replace_string(&GetSValue()->u.string,w2c.out());
	return S_OK;
}


STDMETHODIMP CMValue::get_MappingCount(int * pVal)
{
	// TODO: Add your implementation code here
	if(!pVal)return S_FALSE;
	if(Type()!=VP_MAPPING)return S_FALSE;
	if(!GetSValue()->u.map)return S_OK;
	*pVal=GetSValue()->u.map->count;
	return S_OK;
}

extern "C" array_t * _mapping_indices(mapping_t *);
extern "C" svalue_t * _find_in_mapping(mapping_t *,svalue_t *);
extern "C" svalue_t * _insert_in_mapping(mapping_t *,char *);
STDMETHODIMP CMValue::get_MappingKeys(IMArray * * pVal)
{
	// TODO: Add your implementation code here
	if(!pVal)return S_FALSE;
	if(Type()!=VP_MAPPING)return S_FALSE;
	svalue_t st;
	st.u.arr=_mapping_indices(GetSValue()->u.map);
	st.type=T_ARRAY;
	CComObject<CMValue> *p;
	p=new CComObject<CMValue>;
	p->Create(&st);
	p->AddRef();
	*pVal=p;
	return S_OK;
}

STDMETHODIMP CMValue::Query(BSTR sKey, IMValue * * pVal)
{
	// TODO: Add your implementation code here
	if(!pVal)return S_FALSE;
	if(Type()!=VP_MAPPING)return S_FALSE;
	Cw2c w2c;
	svalue_t st;
	svalue_t *pst;
	w2c.in(sKey);
	SysFreeString(sKey);
	st.type=T_STRING;
	st.subtype=0;
	st.u.string=w2c.out();
	pst=_find_in_mapping(GetSValue()->u.map,&st);
	
	CComObject<CMValue> *p;
	p=new CComObject<CMValue>;
	p->Create(pst);
	p->AddRef();
	*pVal=p;
	return S_OK;
}

STDMETHODIMP CMValue::Map(BSTR sKey, IDispatch * pVal)
{
	// TODO: Add your implementation code here
	if(!pVal)return S_FALSE;
	if(Type()!=VP_MAPPING)return S_FALSE;
	Cw2c w2c;
	svalue_t *pst;
	CComObject<CMValue> *p;
	pVal->QueryInterface(IID_IMValue,(void **)&p);
	if(!p)return S_FALSE;
	w2c.in(sKey);
	SysFreeString(sKey);
	pst=_insert_in_mapping(GetSValue()->u.map,w2c.out());
    if(!pst){
        p->Release();
        return S_FALSE;
    }
	_assign_svalue_no_free(pst,p->GetSValue());
    p->Release();
	return S_OK;
}

STDMETHODIMP CMValue::get_Extend(IDispatch * * pVal)
{
	// TODO: Add your implementation code here
	if(!pVal)return S_FALSE;

	VALUETYPE vt;
	vt=Type();
	switch(vt){
	case VP_NUMBER :_InternalQueryInterface(IID_IMNumber, (void **)pVal);break;
	case VP_STRING :_InternalQueryInterface(IID_IMString, (void **)pVal);break;
	case VP_REAL   :_InternalQueryInterface(IID_IMReal,   (void **)pVal);break;
	case VP_ARRAY  :_InternalQueryInterface(IID_IMArray,  (void **)pVal);break;
	case VP_CLASS  :_InternalQueryInterface(IID_IMClass,  (void **)pVal);break;
	case VP_OBJECT :_InternalQueryInterface(IID_IMObject, (void **)pVal);break;
	case VP_MAPPING:_InternalQueryInterface(IID_IMMapping,(void **)pVal);break;
	case VP_BUFFER :_InternalQueryInterface(IID_IMBuffer, (void **)pVal);break;
	}
	return S_OK;
}

STDMETHODIMP CMValue::get_Program(IMProgram * * pVal)
{
	// TODO: Add your implementation code here
	if(!pVal)return S_FALSE;
	if(Type()!=VP_OBJECT)return S_FALSE;
	CComObject<CMProgram> *p;
	p=new CComObject<CMProgram>;
	p->Create(GetSValue()->u.ob);
	p->AddRef();
	*pVal=p;
	return S_OK;
}

